/******************************************************************************
 *
 *  GTBE_mainTestDRDY.c - Full PLL test Program with hardware interface.  Uses the
 *   Georgia Tech Back-end interface board along with a Tiva C Launchpad
 *
 *  Author: Curtis Mayberry
 *  Georgia Tech IMEMS
 *  rev1 March 2014
 *
 *  Originally written for the MRIG gyroscope project
 *
 *  GT BE Peripherals:
 *   ADC
 *    GPIO PB5
 *    SSI2
 *    M1PWM5
 *   DAC
 *    GPIO PE1 - PE3
 *    SSI0
 *   Data Storage
 *    Flash Memory (see memory map below)
 *   Processing
 *    FPU
 *   Communications
 *    UART0
 *    uDMA
 *
 *  GT BE Hardware Connections:
 *   ADC: ADS1278
 *    INPUTS
 *     TEST0		-> GPIO PE4: PE4
 *     TEST1		-> GPIO PE4: PE4
 *     CLKDIV		-> GPIO PE5: PE5
 *     ~SYNC		-> GPIO PE0: PE0
 *     CLK			-> M1PWM5  : PF1 (option: hardware jumper)
 *     CLK			-> SSI2_CLK: PB4 (option: hardware jumper)
 *     MODE0		-> GPIO PA6: PA6
 *	   MODE1		-> GPIO PA7: PA7
 *	   FORMAT0		-> GPIO PC4: PC4
 *	   FORMAT1		-> GPIO PC5: PC5
 *	   FORMAT2		-> GPIO PC6: PC6
 *	   SERIAL
 *	   SCLK  		-> SSI2_CLK: PB4
 *	   ~DRDY/ FSYNC -> GPIO PB5: PB5 (CS) (SPI Format: ~DRDY)
 *	   DOUT1        -> SSI2_RX:  PB6 (MISO)
 *	   DOUT2		-> GPIO PB0: PB2
 *	   DOUT3		-> GPIO PB1: PB1
 *	   DOUT4		-> GPIO PB2: PB2
 *	   DOUT5		-> GPIO PB3: PB3
 *	   DOUT6		-> GPIO PB7: PB7
 *	   DOUT7		-> GPIO PD6: PD6
 *	   DOUT8		-> GPIO PD7: PD7
 *    OUTPUTS
 *	   NONE
 *	 DAC
 *    INPUTS
 *     ~LDAC_Forcer -> GPIO PE1
 *     ~LDAC_Quad   -> GPIO PE2
 *     ~CLR         -> GPIO PE3
 *	   SERIAL (SPI)
 *     SCLK         -> SSI0_CLK: PA2
 *     ~SYNC		-> SSI0_FSS: PA3 (CS)
 *     SDO		    -> SSI0_RX:  PA4 (MISO)
 *     SDIN         -> SSI0_TX:  PA5 (MOSI)
 *    OUTPUTS
 *     All 4 outputs of each DAC may be used
 *
 *  This work is licensed under the Creative Commons Attribution-ShareAlike 3.0
 *  Unported License. To view a copy of this license, visit
 *  http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative
 *  Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
 *
 ******************************************************************************/

#include <stdint.h>
#include <stdbool.h>
#include <math.h>
#include "inc/hw_memmap.h"
#include "inc/hw_ssi.h"
#include "inc/hw_types.h"
#include "inc/hw_ints.h"

// Tivaware
#include "driverlib/rom.h"
#include "driverlib/ssi.h"
#include "driverlib/sysctl.h"
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/fpu.h"
#include "driverlib/pwm.h"
#include "driverlib/interrupt.h"
#include "driverlib/uart.h"
#include "driverlib/flash.h"
//#include "driverlib/timer.h"
//#include "driverlib/udma.h"

// Launchpad Drivers
//#include "examples/boards/ek-tm4c123gxl/drivers/rgb.c"

// GTBE Lib
#include "dac_ad5754.h"
#include "adc_ads1278.h"
#include "tw_extension.h"

#ifndef M_PI
#define M_PI                    3.14159265358979323846
#endif

/**************
 * Parameters *
 **************/

// Flash Memory Map
#define FLASH_ADDR_CODE   0x0000 // 0x0000 - 0x2800 10KB Code (Protected - Execute Only)
#define FLASH_ADDR_SIG_I  0x2800 // 0x2800 - 0x4800  8KB gpADC_reading (Data Storage)
#define FLASH_ADDR_MSIG_I 0x4800 // 0x8800 - 0x6800  8KB gp_msig_I (Data Storage)
#define FLASH_ADDR_MSIG_Q 0x6800 // 0x6800 - 0x8800  8KB gp_msig_Q (Data Storage)
#define FLASH_ADDR_ERR    0x8800 // 0x8800 - 0xA800  8KB gp_err (Data Storage)
#define FLASH_ADDR_PHASE  0xA800 // 0xA800 - 0xB000  8KB gp_currPhase (Data Storage)
#define FLASH_ADDR_NCO_I  0xB000 // 0xB000 - 0xB800  8KB gp_nco_I (Data Storage)
#define FLASH_ADDR_NCO_Q  0xB800 // 0xB800 - 0xC000  8KB gp_nco_Q (Data Storage)

#define FLASH_SIZE_CODE   0x2800 // Size of each buffer
#define FLASH_SIZE_DATA   0x2000

#define FLASH_START_DATA  FLASH_ADDR_SIG_I // Start address of data in flash memory
#define FLASH_LENGTH_DATA 0x9800 // Total length of data
								 // = 0xC000 - 0x2800

/**************
 * Prototypes *
 **************/
void Timer2IntHandlerDACout(void);

/*********************
 * Hardware Settings *
 *********************/
#define BIN TWOS_COMPLEMENT // DAC data format in bipolar modes

/*********************
 * Global Variables
 *********************/
//#define BUFFER_SIZE 1024
//uint32_t ADCdatabufferByte2[BUFFER_SIZE];
//uint32_t ADCdatabufferByte1[BUFFER_SIZE];
//uint32_t ADCdatabufferByte0[BUFFER_SIZE];
//uint32_t ADC_Reading[BUFFER_SIZE];
//float ADC_ReadingV[BUFFER_SIZE];
//uint32_t bufferIdx = 0;
//uint32_t bufferIdxPrevious = 0;

bool g_dataProcessing;
bool g_dataReady = false;

#define BUFFER_SIZE 1
// ADC Buffers
uint32_t gADC_dataBufferByte2[1];
uint32_t gADC_dataBufferByte1[1];
uint32_t gADC_dataBufferByte0[1];
uint32_t gADC_reading[1];

// DAC output buffer
int32_t gDAC_outputBuffer[BUFFER_SIZE];
// Signal Gain
uint32_t A = 2;
// UART Command Handling
int32_t g_UARTCommand;

// DSP variables
floatFlash g_sig_I;

/******************
 * GPIO Functions *
 ******************/
/**
 * An Interrupt handler which executes each time ~DRDY goes low.  The
 **/
void intHandlerDRDY(void) {
	uint32_t intStatus;
	intStatus = GPIOIntStatus(GPIO_PORTB_BASE, true);
	GPIOIntClear(GPIO_PORTB_BASE, intStatus);
	if(intStatus == GPIO_INT_PIN_5) {
		// Receive Each byte over SSI
		ROM_SSIDataPut(SSI2_BASE,0x00000000); // Byte 2
		ROM_SSIDataPut(SSI2_BASE,0x00000000); // Byte 1
		ROM_SSIDataPut(SSI2_BASE,0x00000000); // Byte 0

		// Transfer each byte to the buffers
		ROM_SSIDataGet(SSI2_BASE,&gADC_dataBufferByte2[0]);
		ROM_SSIDataGet(SSI2_BASE,&gADC_dataBufferByte1[0]);
		ROM_SSIDataGet(SSI2_BASE,&gADC_dataBufferByte0[0]);

		DACd_updateDataDig(DAC_ADDR_A | DAC_ADDR_NONE_EH, gDAC_outputBuffer[0], 0x00000000);

		g_dataReady = true;
	}
}

/******************
 * UART Functions *
 ******************/
/**
 * Initializes the UART
 **/
 void initUART0(void) {
	 ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
	 ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

	 ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
	 ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
	 ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

	 ROM_UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
	 (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));
 }

/**
 * Initializes the UART interrupt
 **/
 void initUart0Interrupt(void) {
	 ROM_UARTIntEnable(UART0_BASE, UART_INT_RX);
 }

/**
 * Receives commands for the device
 **/
 void uart0MonitorISR(void) {
	 g_UARTCommand = UARTCharGetNonBlocking(UART0_BASE);
 }

/******************
 * NVIC Functions *
 ******************/
/**
 * Sets the priority of the interrupts
 *  The ~DRDY sample ISR is given highest priority
 *  The UART RX ISR is given lower priority
 *  Smaller numbers correspond to higher interrupt priorities; priority 0 is the highest
 *  interrupt priority.
 **/
 initIntPriority(void) {
	 // Highest Priority
	 ROM_IntPrioritySet(INT_GPIOB, 0x00);
	 ROM_IntPrioritySet(INT_SSI0, 0x20);
	 ROM_IntPrioritySet(UART_INT_RX, 0xE0);
	 // Lowest Priority

 }

int main(void) {

	/* System Initialization */
	// Set system clock to 80 MHz (400MHz main PLL (divided by 5 - uses DIV400 bit)  [16MHz external xtal drives PLL]
	ROM_SysCtlClockSet(SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHZ);
	twe_initFPU();
	twe_initUART0();


	/* DAC initialization */
	DAC_initDAC(DAC_RANGE_PM5V, DAC_PWR_PUA | DAC_PWR_PUB);
	DAC_initSSI0Int();

	/* ADC initialization */
	ADC_initADC();
	ADC_initDRDYint();

	// Initialize Flash
	twe_initFlash(FLASH_ADDR_CODE, 0x0,
				  FLASH_START_DATA,FLASH_LENGTH_DATA); // Doesn't set protection but does erase the data
	g_sig_I.address = FLASH_ADDR_SIG_I;

	 int32_t flashStatus;
	 uint32_t flashError = 0;
	// Process data between samples
	while(1) {
		// Collect Data
		if(g_dataReady == true) {

			g_dataReady = false;
			g_dataProcessing = true;
			gADC_reading[0] = ((((gADC_dataBufferByte2[0]<<16)+(gADC_dataBufferByte1[0]<<8)+(gADC_dataBufferByte0[0]))) >> 8);
			/* Causes problems with DAC output
			g_sig_I.data.fn[0] = (float) gADC_reading[0];
			if(g_sig_I.address < 0x4800) {
				flashStatus = FlashProgram(g_sig_I.data.uintn,g_sig_I.address,4);
				if(flashStatus != 0) {
					flashError++;
				}
			}
			*/
			g_sig_I.address += 4;
			SysCtlDelay(100);
			gDAC_outputBuffer[0] = A * gADC_reading[0];
			g_dataProcessing = false;
			//if(g_sig_I.address > 0x4800) {
				//while(1) {} // Program is complete when the flash is full.
			//}
		}
	}
}
